import { _decorator, Component, Label, tween, Tween, UIOpacity, UITransform, v3, Vec2, Vec3, Widget } from 'cc';
import { DataProxy } from '../../../../frame/A-LIB/sources/lib.b.data';
import { AudioManager } from '../../../../frame/component/audio-manager';
import { ClientAPI } from '../../../api/api.client';
import GameDC from '../../../data/data.game.center';
import GameAsset from '../../../manager/asset.manager';
import DataManager from '../../../manager/data.manager';
import { DrawerStash } from '../../structure/drawer.stash';
import { DrawerStore } from '../../structure/drawer.store';
import { Tile } from '../../structure/tile';
import { Float } from '../float';
import { Guide } from '../guide';
import { Popup } from '../pop-up';
import { GameBoard } from './game.board';
const { ccclass, property } = _decorator;

@ccclass('GameContainer')
export class GameContainer extends Component {
	@property(GameBoard)
	private board: GameBoard = null;
	@property(DrawerStore)
	private Dstore: DrawerStore = null;
	@property(DrawerStash)
	private Dstash: DrawerStash = null;

	private ui_drawer_container: UITransform;
	private ui_temp: UITransform;

	private va_drawer_container: mtec.cc.VecAssist;

	private listen_list: Array<ReturnType<typeof DataProxy.follow>> = [];

	protected onLoad(){
		this.init();
		this.listening();
	}

	protected start(){
		let wgt = this.node.getComponent(Widget);
		if(wgt) wgt.updateAlignment();

		this.node.children.forEach(n=>{
			let wgt = n.getComponent(Widget);
			if(wgt) wgt.updateAlignment();
		});

		this.va_drawer_container.getPosition('center', 'over_bottom');
		this.ui_drawer_container.node.setPosition(this.va_drawer_container.vec);

		GameBoard.onSelectTile(this.onSelectTile.bind(this));
		DrawerStash.onSelectRecord(this.onSelectRecordFromStash.bind(this));
		this.Dstash.onClean(this.onDrawerClean.bind(this));
		this.Dstore.onClean(this.onDrawerClean.bind(this));
		this.Dstore.onRemoveTiles(this.onStoreRemoveTiles.bind(this));
		this.Dstore.onPadded(this.onStorePadded.bind(this));
	}

	protected onDestroy(){
		this.listen_list.forEach(reg=>DataProxy.cancel(reg));
	}

	private init(){
		this.ui_drawer_container = this.node.getChildByName('drawer-container').getComponent(UITransform);
		this.ui_temp = this.node.getChildByName('temp').getComponent(UITransform);

		this.va_drawer_container = new mtec.cc.VecAssist(this.ui_drawer_container.node);
	}

	private listening(){
		this.listen_list = [];

		this.listen_list.push(
			DataProxy.follow(GameDC.Trigger, 'UIGame', (_, show)=>this.onUIGameTrigger(show, _), false),
			DataProxy.follow(GameDC.Trigger, 'STASH', (_, force)=> this.stashTile(force) , false),
			DataProxy.follow(GameDC.Trigger, 'REVOKE', (_, force)=> this.revokeTile(force) , false),
			DataProxy.follow(GameDC.Trigger, 'SHUFFLE', (_, force)=> this.shuffle(force) , false),
			DataProxy.follow(GameDC.Trigger, 'LoadRound', (_, round)=> this.loadRound(round) , false)
		);

		if(GameDC.User.drawer_lock){
			let icon_drawer_lock = this.ui_drawer_container.node.getChildByName('icon-lock');
			let uiop_bubble = this.ui_drawer_container.node.getChildByName('bubble').getComponent(UIOpacity);
			uiop_bubble.node.getChildByName('lbl-a').getComponent(Label).string = '80%';
			uiop_bubble.node.getChildByName('lbl-b').getComponent(Label).string = 'Easier';
			let bubble_origin = new Vec3(400, 505, uiop_bubble.node.position.z);
			let bubble_target = new Vec3(400, 530, uiop_bubble.node.position.z);
			icon_drawer_lock.active = true;
			uiop_bubble.node.active = true;
			uiop_bubble.opacity = 0;

			let lock_list: Array<ReturnType<typeof DataProxy.follow>> = [];

			lock_list.push(
				DataProxy.follow(GameDC.User, 'drawer_lock', (_, lock)=>{
					if(lock){
						return void 0;
					}

					lock_list.forEach(reg=>DataProxy.cancel(reg));

					Tween.stopAllByTarget(uiop_bubble);
					Tween.stopAllByTarget(uiop_bubble.node);
					icon_drawer_lock.active = false;
					uiop_bubble.node.active = false;
				}, false),
				DataProxy.follow(GameDC.Trigger, 'HintLock', (_, hint)=>{
					if(hint==_){
						return void 0;
					}

					if(hint){
						uiop_bubble.node.active = true;
						Tween.stopAllByTarget(uiop_bubble);
						Tween.stopAllByTarget(uiop_bubble.node);

						uiop_bubble.opacity = 255;
						uiop_bubble.node.setPosition(bubble_origin);

						tween(uiop_bubble.node)
						.to(0.2, {position: bubble_target})
						.to(0.2, {position: bubble_origin})
						.union().repeat(3).delay(0.6).union()
						.repeatForever().start();
					}else{
						tween(uiop_bubble)
						.to(0.5, {opacity: 0})
						.call(()=>{
							Tween.stopAllByTarget(uiop_bubble);
							Tween.stopAllByTarget(uiop_bubble.node);
							uiop_bubble.node.active = false;
						}).start();
					}
				}, false),
				DataProxy.follow(GameDC.Trigger, 'UIHome', (_, show)=>{
					if(show){
						if(!uiop_bubble.node.active && GameDC.Trigger.HintLock){
							uiop_bubble.node.active = true;
							Tween.stopAllByTarget(uiop_bubble);
							Tween.stopAllByTarget(uiop_bubble.node);

							uiop_bubble.opacity = 255;
							uiop_bubble.node.setPosition(bubble_origin);

							tween(uiop_bubble.node)
							.to(0.2, {position: bubble_target})
							.to(0.2, {position: bubble_origin})
							.union().repeat(3).delay(0.6).union()
							.repeatForever().start();
						}
					}else{
						tween(uiop_bubble)
						.to(0.5, {opacity: 0})
						.call(()=>{
							Tween.stopAllByTarget(uiop_bubble);
							Tween.stopAllByTarget(uiop_bubble.node);
							uiop_bubble.node.active = false;
						}).start();
					}
				}, false)
			);
		}else{
			['icon-lock', 'bubble'].forEach(n=>this.ui_drawer_container.node.getChildByName(n).active = false);
		}
	}

	private onUIGameTrigger(show: boolean, ov: boolean){
		if(ov===show){
			return void 0;
		}

		if(show){
			this.enterDrawer();
		}else{
			this.leaveDrawer();
		}
	}

	private enterDrawer(duration?: number){
		duration = duration ?? 0.5;

		this.va_drawer_container.getPosition('center', 'bottom');

		Tween.stopAllByTarget(this.ui_drawer_container.node);
		tween(this.ui_drawer_container.node)
		.to(duration, {position: this.va_drawer_container.vec}, {easing: 'cubicOut'})
		.start();
	}

	private leaveDrawer(duration?: number){
		duration = duration ?? 0.5;

		this.va_drawer_container.getPosition('center', 'over_bottom');

		Tween.stopAllByTarget(this.ui_drawer_container.node);
		tween(this.ui_drawer_container.node)
		.to(duration, {position: this.va_drawer_container.vec}, {easing: 'cubicIn'})
		.call(()=>{
			this.Dstash.clean();
			this.Dstore.clean();
			this.loadRound(GameDC.Cache.round_curr);
		}).start();
	}

	private onSelectRecordFromStash(record: {tier: number, coor: Vec2, tile: Tile}){
		if(!(this.Dstore.residue>0)) return void 0;
		this.Dstash.removeRecord(record.tile);

		Tween.stopAllByTarget(record.tile.node);

		let pading_info = this.Dstore.padding(record);
		if(!pading_info) return void 0;

		let target_positon = this.ui_temp.convertToNodeSpaceAR(pading_info.world_position);
		let position = this.ui_temp.convertToNodeSpaceAR(record.tile.node.worldPosition);
		record.tile.node.removeFromParent();
		record.tile.node.setParent(this.ui_temp.node);
		record.tile.node.setPosition(position);

		let duration = Vec3.subtract(v3(), target_positon, position).length() / Math.max(record.tile.width, record.tile.height) * 0.06;

		tween(record.tile.node)
		.to(duration, {position: target_positon}, {easing: 'backIn'})
		.call(()=>this.Dstore.padded(pading_info.token))
		.start();
	}

	private onSelectTile(record: {tier: number, coor: Vec2, tile: Tile}){
		if(!(this.Dstore.residue>0)) return void 0;
		AudioManager.playEffect(AudioManager.EAudio.EF_CLICK);
		this.board.removeTile(record.tier, record.tile);

		Tween.stopAllByTarget(record.tile.node);

		let pading_info = this.Dstore.padding(record);
		if(!pading_info) return void 0;

		let target_positon = this.ui_temp.convertToNodeSpaceAR(pading_info.world_position);
		let position = this.ui_temp.convertToNodeSpaceAR(record.tile.node.worldPosition);
		record.tile.node.removeFromParent();
		record.tile.node.setParent(this.ui_temp.node);
		record.tile.node.setPosition(position);

		let duration = Vec3.subtract(v3(), target_positon, position).length() / Math.max(record.tile.width, record.tile.height) * 0.06;

		tween(record.tile.node)
		.to(duration, {position: target_positon}, {easing: 'backIn'})
		.call(()=>this.Dstore.padded(pading_info.token))
		.start();
	}

	private onStorePadded(record: {tier: number, coor: Vec2, tile: Tile, token?: string}, full: boolean){
		if(full){
			mtec.log.tag('GameOver: red');
			this.GameOver(false);
		}

		if(GameDC.User.drawer_lock){
			GameDC.Trigger.HintLock = this.Dstore.residue<=2;
		}
	}

	private onDrawerClean(tile_list: Tile[]){
		tile_list.forEach(t=>GameBoard.recycleTile(t));
	}

	private async onStoreRemoveTiles(tile_list: Tile[], world_position: Vec3){
		tile_list.forEach(t=>GameBoard.recycleTile(t));

		AudioManager.playEffect(AudioManager.EAudio.EF_REMOVE);
		Float.XX(world_position, 3);

		GameDC.Cache.remove_count++;
		GameDC.Status.remove_tile_count += tile_list.length;

		if(GameDC.User.adblock){
			if(GameDC.Cache.round_curr >= 4){
				let ad_type = DataManager.checkForcePop();
				if(ad_type){
					await ClientAPI.AD(ad_type);
				}
			}
		}

		if(GameDC.Status.remove_tile_count==this.board.tileCount){
			mtec.log.tag('GameOver: green');
			this.GameOver(true);
		}
	}

	private stashTile(force: boolean){
		if(!force && !(GameDC.Status.prop_stash>0)){
			return void 0;
		}

		let count = Math.min(3, this.Dstore.tileCount);
		if(count <= 0){
			Float.Hint('No cards in the bottom slot');
			return void 0;
		}

		count = Math.min(count, this.Dstash.residue);
		if(count <= 0){
			Float.Hint('The area is full, props cannot be used');
			return void 0;
		}

		let list = this.Dstore.unshiftTile(count);

		if(list.length<=0) return void 0;

		AudioManager.playEffect(AudioManager.EAudio.EF_REVOKE);

		list.forEach(record=>{
			Tween.stopAllByTarget(record.tile.node);

			let position = this.ui_temp.convertToNodeSpaceAR(record.tile.node.worldPosition);
			let padding_info = this.Dstash.padding(record);
			let target_position = this.ui_temp.convertToNodeSpaceAR(padding_info.world_position);

			record.tile.node.removeFromParent();
			record.tile.node.setParent(this.ui_temp.node);
			record.tile.node.setPosition(position);

			let duration = Vec3.subtract(v3(), target_position, position).length() / Math.max(record.tile.width, record.tile.height) * 0.06;

			tween(record.tile.node)
			.to(duration, {position: target_position}, {easing: 'cubicOut'})
			.call(()=>this.Dstash.padded(padding_info.token))
			.start();
		});

		if(force){
			return void 0;
		}

		GameDC.Status.prop_stash--;
	}

	private revokeTile(force: boolean){
		if(!force && !(GameDC.Status.prop_revoke>0)){
			return void 0;
		}

		let record = this.Dstore.popLastRecord();

		if(!record){
			Float.Hint('No cards in the bottom slot');
			return void 0;
		}

		AudioManager.playEffect(AudioManager.EAudio.EF_REVOKE);

		Tween.stopAllByTarget(record.tile.node);

		let position = this.ui_temp.convertToNodeSpaceAR(record.tile.node.worldPosition);
		let target_position = this.ui_temp.convertToNodeSpaceAR(this.board.appendingTile(record.tier, record.coor, record.tile));

		record.tile.node.removeFromParent();
		record.tile.node.setParent(this.ui_temp.node);
		record.tile.node.setPosition(position);

		let duration = Vec3.subtract(v3(), target_position, position).length() / Math.max(record.tile.width, record.tile.height) * 0.06;

		tween(record.tile.node)
		.to(duration, {position: target_position}, {easing: 'cubicOut'})
		.call(()=>this.board.appendedTile(record.tier, record.coor, record.tile))
		.start();

		if(force){
			return void 0;
		}

		GameDC.Status.prop_revoke--;
	}

	private shuffle(force: boolean){
		if(!force && !(GameDC.Status.prop_shuffle>0)){
			return void 0;
		}

		this.board.shuffle();
		AudioManager.playEffect(AudioManager.EAudio.EF_SHUFFLE);

		if(force){
			return void 0;
		}

		GameDC.Status.prop_shuffle--;
	}

	private async GameOver(victory: boolean){
		if(GameDC.Status.gameover!==undefined) return void 0;

		GameDC.Trigger.GameOver = victory;
		GameDC.Status.gameover = victory;
		let round = GameDC.Cache.round_curr;

		AudioManager.pauseBgm();
		if(victory){
			GameDC.Cache.round_last = round;
			DataManager.userPoint('FruitLevelSuccess', {fruitLevel: round});
			AudioManager.playEffect(AudioManager.EAudio.BGM_VICTORY);
			await Popup.Victory(round);
			if(GameDC.checkGuideID(6)){
				await Guide.Wait(6);
			}

			GameDC.Cache.round_curr = Math.max(1, Math.min(4, round+1));
			GameDC.Trigger.UIGame = false;
			GameDC.Trigger.UIHome = false;
			GameDC.Trigger.UITrans = true;
		}else{
			let resurgence = GameDC.Status.resurgence>0;
			if(resurgence) resurgence = await Popup.Resurgence();

			if(resurgence){
				GameDC.Status.gameover = undefined;
				GameDC.Status.resurgence--;
				GameDC.Trigger.STASH = true;
			}else{
				GameDC.Cache.round_last = round;
				DataManager.userPoint('FruitLevelFail', {fruitLevel: round});
				AudioManager.playEffect(AudioManager.EAudio.BGM_DEFEAT);
				await Popup.Defeat(round);

				GameDC.Trigger.UIGame = false;
				GameDC.Trigger.UIHome = false;
				GameDC.Trigger.UITrans = true;
			}
		}
		AudioManager.playBGM();
	}

	private async loadRound(round: number){
		round = Math.max(1, Math.min(4, round));
		DataManager.cleanGameStatus();
		DataManager.userPoint('FruitLevel', {fruitLevel: round});

		await this.board.renderBoard(await GameAsset.loadRoundData(round));

		if(round>=4){
			this.board.setLoop(await GameAsset.loadRoundLayout('level_zero'));
		}
	}

	private onClickLock(){
		DataManager.userPoint('WishAddSpace');
		Popup.DrawerLock();
	}
}

